﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Athena.Plugins;

namespace Athena.Core
{
    [Serializable()]
    public abstract class Container : Item
    {
        /// <summary>
        /// stores all the items indexed by their IDs
        /// </summary>
        protected Hashtable _Items;

        /// <summary>
        /// The copy constructor
        /// </summary>
        /// <param name="copy">the module to copy</param>
        public Container(Container copy)
            : base(copy.ItemType, copy.ID)
        {
            int items = copy._Items.Count;
            _Items = new Hashtable();

            //cloning the edges requires keeping track of duplicated nodes

            List<Item> originals = new List<Item>(),
                       duplicates = new List<Item>();

            //clone the nodes

            foreach (Item i in copy._Items.Values)
            {
                if (!(i is Edge))    //dont copy edges, because they need to be re-made
                {
                    Item temp = (Item)i.Clone();

                    originals.Add((Item)i);   //keep record: duplicate[i] = copy of original[i]
                    duplicates.Add(temp);

                    _Items.Add(temp.ID, temp);         //add each node to the items

                }
            }

            //now we have copied all nodes and have a list of original-duplicate pairs
            //lets make edges

            foreach (Item i in copy._Items)
            {
                if (i is Edge)
                {
                    Node[] originalInputNodes = ((Edge)i).Reactants; //get its inputs
                    List<Node> duplicateInputNodes = new List<Node>(originalInputNodes.Length);

                    Node[] originalOutputNodes = ((Edge)i).Products; //get its outputs
                    List<Node> duplicateOutputNodes = new List<Node>(originalOutputNodes.Length);

                    foreach (Node n in originalInputNodes)    //for each input node in this edge
                    {
                        for (int j = 0; j < originals.Count; ++j)   //find the index of
                        {
                            if (n == originals[j] && duplicates[j] is Node)                   //the original node
                            {
                                duplicateInputNodes.Add((Node)duplicates[j]);  //add the corresponding duplicate node to the new inputs list
                                break;
                            }
                        }
                    }

                    foreach (Node n in originalOutputNodes)    //for each output node in this edge
                    {
                        for (int j = 0; j < originals.Count; ++j)   //find the index of
                        {
                            if (n == originals[j] && duplicates[j] is Node)                   //the original node
                            {
                                duplicateOutputNodes.Add((Node)duplicates[j]);  //add the corresponding duplicate node to the new output list
                                break;
                            }
                        }
                    }

                    //make a new edge using the correct duplicates and the original rate law
                    Edge edge = new Edge(duplicateInputNodes, duplicateOutputNodes, ((Edge)i).Rate);

                    _Items.Add(edge.ID, edge);
                }
            }
        }

        /// <summary>
        /// constructor
        /// </summary>
        public Container()
        {
            _Items = new Hashtable();
        }

        /// <summary>
        /// constructor
        /// </summary>
        public Container(string type, string ID)
            : base(type, ID)
        {
            _Items = new Hashtable();
        }

        /// <summary>
        /// Checks whether this Container contains an item with the given ID
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        public virtual bool Contains(string ID)
        {
            /*if (_Items == null) _Items = new Hashtable();

            foreach (Item i in _Items.Values)
            {
                if (i is Container)
                {
                    if (((Container)i).Contains(ID))
                        return true;
                }
            }*/
            return _Items.ContainsKey(ID);
        }
        /*
        /// <summary>
        /// Checks if the following ID is appearing more than once in this container
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        public virtual bool DuplicateName(string ID, Item current)
        {
            if (_Items == null) _Items = new Hashtable();

            foreach (Item i in _Items.Values)
            {
                if (i.ID.Equals(ID) && i != current) return true;
                if (i is Container)
                {
                    if (((Container)i).DuplicateName(ID,current))
                        return true;
                }
            }
            return false;
        }
        
        /// <summary>
        /// Renames all items with a duplicate id
        /// </summary>
        public virtual void RenameDuplicateIDs()
        {
            ICollection<Item> items = (ICollection<Item>)AllItems;
            foreach (Item i in items)
            {
                if (DuplicateName(i.ID, i)) i.ID = RequestNewID(i.ID);
            }
        }*/

        /// <summary>
        /// Checks whether this Container contains the given item 
        /// (recursively checks containers within this container)
        /// </summary>
        /// <param name="ID"></param>
        /// <returns></returns>
        public virtual bool Contains(Item item)
        {
            if (_Items == null || _Items.Count < 1) return false;

            foreach (Item i in _Items.Values)
            {
                if (i == item) return true;
                if (i is Container)
                {
                    if (((Container)i).Contains(item))
                        return true;
                }
            }
            return false;
        }
        /// <summary>
        /// Checks whether this module contains an item of the given type
        /// (recursively checks containers within this container)
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public virtual bool ContainsType(Type type)
        {
            if (_Items == null) _Items = new Hashtable();

            foreach (Item i in _Items.Values)
            {
                if (i.GetType().IsSubclassOf(type) || i.GetType().Equals(type))
                    return true;

                if (i is Container && i != this)
                {
                    if (((Container)i).ContainsType(type))
                        return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Add an item into the Container. If the item is a module, all the nodes and reactions in that
        /// module are added
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public virtual bool AddItem(Item item)
        {
            if (_Items == null) _Items = new Hashtable();

            if (item == null || item == this || item is GlobalSpecies) return true;

            if (_Items.ContainsValue(item))
            {
                if (item.Parent != this) item.Parent = this;
                return true;
            }

            if (_Items.ContainsKey(item.ID)) item.ID = RequestNewID(item.ID);

            if (!ValidID(item.ID)) return false;
            
            _Items[item.ID] = item;

            if (item.Parent != this) item.Parent = this;

            if (item is Edge || item is Part)
            {
                if (item is Edge)
                    ((Edge)item).Update();
                if (item is Part)
                {
                    ((Part)item).PoPS_Left.Update();
                    ((Part)item).PoPS_Right.Update();
                }
            }

            return true;
        }
        /// <summary>
        /// Add a series of items into this container
        /// </summary>
        /// <param name="items"></param>
        public virtual void AddItem(params Item[] items)
        {
            foreach (Item i in items)
                AddItem(i);
        }
        /// <summary>
        /// Add an item into the Container. If the item is a module, all the nodes and reactions in that
        /// module are added
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public virtual bool AddItem(Item item, Item oldParent)
        {
            return AddItem(item);
        }

        /// <summary>
        /// Remove an item from the Container and from all the modules in the Container
        /// </summary>
        /// <param name="item"></param>
        public virtual void RemoveItem(Item item, Item newParent)
        {
            RemoveItem(item);
        }

        /// <summary>
        /// Remove an item from the Container and from all the modules in the Container
        /// </summary>
        /// <param name="item"></param>
        public virtual void RemoveItem(Item item)
        {
            if (item == null) return;

            if (item.Parent == this)
            {
                item.Parent = null;
                return;
            }

            if (_Items == null) _Items = new Hashtable();

            //if (!Contains(item)) return;

            if (_Items.ContainsValue(item))
            {
                string id = item.ID;
                foreach (string s in _Items.Keys)
                {
                    if (_Items[s] == item)
                    {
                        id = s;
                        break;
                    }
                }
                _Items.Remove(id);
            }

            foreach (Item i in _Items.Values)
            {
                if (i is Container && item.Parent != i)
                {
                    ((Container)i).RemoveItem(item);
                }
            }            
        }

        /// <summary>
        /// Remove all the items in this Container
        /// </summary>
        public override void Remove()
        {
            base.Remove();
            List<Item> items = new List<Item>();
            foreach (Item i in _Items.Values)
                items.Add(i);

            foreach (Item i in items)
            {
                i.Parent = null;
            }

            if (_Items != null)
                _Items.Clear();
        }

        public virtual string RequestNewID(string id)
        {
            if (!Contains(id)) return id;
            if (!string.IsNullOrEmpty(id) && id[id.Length - 1] >= (int)'0' && id[id.Length - 1] <= (int)'9')
                id = id.Substring(0, id.Length - 1);

            int i = 0;
            while (Contains(id + i)) ++i;
            return id + i;
        }

        /// <summary>
        /// Change the ID of one of the items in the Container. Returns false if new ID already exists
        /// </summary>
        /// <param name="oldID"></param>
        /// <param name="newID"></param>
        /// <returns></returns>
        public virtual bool ChangeID(Item item, string oldID, string newID)
        {
            if (oldID == newID) return true;
            if (_Items == null || string.IsNullOrEmpty(oldID) || !Contains(oldID)) return true;

            if (string.IsNullOrEmpty(newID) || Contains(newID) || item.ID != newID) return false;

            if (_Items[oldID] != item) return true;

            foreach (Item i in _Items.Values)
            {
                if (i is Container)
                {
                    ((Container)i).ChangeID(item, oldID, newID);
                }
            }

            if (item != null && !string.IsNullOrEmpty(oldID))
            {
                _Items.Remove(oldID);
            }

            _Items.Add(newID, item);

            List<Core.Edge> edges = LocalReactions;

            foreach (Edge e in edges)
            {
                e.ChangeName(oldID, newID);
            }

            return true;
        }

        /// <summary>
        /// returns all the items that are contained in this Container. Adds
        /// parents names are prefix to each item, regardless of whether or not
        /// it is unique. AllItems is a variant that adds prefixes only when needed
        /// </summary>
        /// <returns></returns>
        public virtual Hashtable AllItemsWithPrefix
        {
            get
            {
                Hashtable items = new Hashtable();

                if (_Items != null && _Items.Count > 0)
                {
                    foreach (string key in _Items.Keys)
                    {
                        Item i = _Items[key] as Item;
                        if (i != null && i != null)
                        {
                            items[key] = i;
                        }
                    }

                    foreach (string key in _Items.Keys)
                    {
                        Item i = _Items[key] as Item;
                        if (i != null && i != null)
                        {
                            if (i is Container)
                            {
                                Hashtable subcomponents = ((Container)i).AllItemsWithPrefix;
                                foreach (string s in subcomponents.Keys)
                                {
                                    Object o = subcomponents[s];
                                    if (o is Item)
                                    {
                                        items[i.ID + "_" + s] = (Item)o;
                                    }
                                }
                            }
                        }
                    }
                }
                return items;
            }
        }

        /// <summary>
        /// returns all the items that are contained in this Container
        /// This function also gets the items inside containers within this container
        /// </summary>
        /// <returns></returns>
        public virtual Hashtable AllItems
        {
            get
            {
                Hashtable items = new Hashtable();
                Hashtable uniqueIDs = new Hashtable();

                if (_Items != null && _Items.Count > 0)
                {
                    foreach (string key in _Items.Keys)
                    {
                        Item i = _Items[key] as Item;
                        if (i != null && i != null)
                        {
                            items[key] = i;
                            uniqueIDs[key] = 1;
                        }
                    }

                    foreach (string key in _Items.Keys)
                    {
                        Item i = _Items[key] as Item;
                        if (i != null && i != null)
                        {
                            if (i is Container)
                            {
                                Hashtable subcomponents = ((Container)i).AllItems;
                                foreach (string str in subcomponents.Keys)
                                {
                                    string s = str;
                                    
                                    if (i is Compartment) s = key + "_" + str;

                                    Object o = subcomponents[str];

                                    if (o is Item)
                                    {
                                        Item n = (Item)o;
                                        Item n2 = n;
                                        if (uniqueIDs.ContainsKey(s))
                                        {
                                            if (items.ContainsKey(s))
                                            {
                                                n2 = (Item)items[s];  //the item with same name
                                                if (n.Depth >= n2.Depth)
                                                {
                                                    Item parent = n.Parent;
                                                    if (parent != null)
                                                    {
                                                        string s2 = n.ID;
                                                        while (items.ContainsKey(s2))
                                                        {
                                                            s2 = parent.ID + "_" + s2;
                                                            parent = parent.Parent;
                                                            if (parent == null || parent == n.Parent)
                                                                break;
                                                        }
                                                        items[s2] = n;
                                                    }
                                                }
                                                else
                                                {
                                                    items[s] = n;
                                                    Item parent = n2.Parent;
                                                    if (parent != null)
                                                    {
                                                        string s2 = n2.ID;
                                                        while (items.ContainsKey(s2))
                                                        {
                                                            s2 = parent.ID + "_" + s2;
                                                            parent = parent.Parent;
                                                            if (parent == null || parent == n2.Parent)
                                                                break;
                                                        }
                                                        items[s2] = n2;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                items[s] = n;
                                            }

                                            n2 = (Item)items[s];
                                            if (n2.ID == s && n2.Parent != this)
                                            {
                                                Item parent = n2.Parent;
                                                if (parent != null)
                                                {
                                                    string s2 = parent.ID + "_" + n2.ID;
                                                    parent = parent.Parent;
                                                    while (items.ContainsKey(s2))
                                                    {
                                                        s2 = parent.ID + "_" + s2;
                                                        parent = parent.Parent;
                                                        if (parent == null || parent == n2.Parent)
                                                            break;
                                                    }
                                                    items.Remove(s);
                                                    items[s2] = n2;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            items[s] = n;
                                        }
                                        uniqueIDs[s] = 1;
                                    }
                                }
                            }
                        }
                    }
                }
                return items;
            }
        }

        /// <summary>
        /// Returns all the nodes that are contained in this Container
        /// This function also gets the nodes inside containers within this container
        /// </summary>
        /// <returns></returns>
        public virtual Hashtable AllNodes
        {
            get
            {
                Hashtable nodes = new Hashtable();
                Hashtable items = AllItems;
                foreach (string s in items.Keys)
                {
                    if (items[s] is Node)
                        nodes[s] = (Node)items[s];
                }
                return nodes;
            }
        }

        /// <summary>
        /// returns all the parts that are contained in this Container
        /// This function also gets the nodes inside containers within this container
        /// </summary>
        /// <returns></returns>
        public virtual Hashtable AllParts
        {
            get
            {
                Hashtable nodes = new Hashtable();
                Hashtable items = AllItems;
                foreach (string s in items.Keys)
                {
                    if (items[s] is Part)
                        nodes[s] = (Part)items[s];
                }
                return nodes;
            }
        }

        /// <summary>
        /// returns all the species that are contained in this Container
        /// This function also gets the species inside containers within this container
        /// </summary>
        /// <returns></returns>
        public virtual Hashtable AllSpecies
        {
            get
            {
                Hashtable nodes = new Hashtable();
                Hashtable items = AllItems;
                foreach (string s in items.Keys)
                {
                    if (items[s] is Species)
                        nodes[s] = (Species)items[s];
                }
                return nodes;
            }
        }

        /// <summary>
        /// Generates a list of edges that represents all the non-regulatory reactions in this Container
        /// This function also gets the reactions inside containers within this container
        /// </summary>
        /// <returns></returns>
        public virtual Hashtable AllReactions
        {
            get
            {
                Hashtable nodes = new Hashtable();
                Hashtable items = AllItems;
                foreach (string s in items.Keys)
                {
                    if (items[s] is Edge && ((Edge)items[s]).IsReaction)
                        nodes[s] = (Edge)items[s];
                }
                return nodes;
            }
        }

        /// <summary>
        /// Generates a list of edges that represent gene regulation in this Container
        /// This function also gets the regulations inside containers within this container
        /// </summary>
        /// <returns></returns>
        public virtual Hashtable AllRegulations            
        {
            get
            {
                Hashtable nodes = new Hashtable();
                Hashtable items = AllItems;
                foreach (string s in items.Keys)
                {
                    if (items[s] is Edge && ((Edge)items[s]).IsRegulation)
                        nodes[s] = (Edge)items[s];
                    else
                        if (items[s] is Part)
                            nodes[s] = ((Part)items[s]).PoPS;
                }
                return nodes;
            }
        }

        /// <summary>
        /// Gets all the items inside this container that are of the given type
        /// Checks containers within container recursively
        /// </summary>
        /// <param name="type">type of interest</param>
        /// <returns>list of items</returns>
        public virtual List<Item> AllItemsOfType(Type type)
        {
            List<Item> itemsoftype = new List<Item>();
            foreach (Item i in _Items.Values)
            {
                if (i.GetType().Equals(type))
                {
                    itemsoftype.Add(i);
                }
                if (i is Container)
                {
                    itemsoftype.AddRange(((Container)i).AllItemsOfType(type));
                }
            }
            return itemsoftype;
        }

        /// <summary>
        /// Get all the reaction edges in this container
        /// This function does NOT check the containers inside this container
        /// also see AllReactions
        /// </summary>
        public virtual List<Edge> LocalReactions
        {
            get
            {
                List<Edge> edges = new List<Edge>();
                foreach (Item i in _Items.Values)
                {
                    if (i is Edge && ((Edge)i).IsReaction)
                        edges.Add((Edge)i);                    
                }
                return edges;
            }
        }

        /// <summary>
        /// Get all the regulation edges in this container
        /// This function does NOT check the containers inside this container
        /// also see AllRegulations
        /// </summary>
        public virtual List<Edge> LocalRegulations
        {
            get
            {
                List<Edge> edges = new List<Edge>();
                foreach (Item i in _Items.Values)
                {
                    if (i is Edge && ((Edge)i).IsRegulation)
                        edges.Add((Edge)i);
                }
                return edges;
            }
        }
        /// <summary>
        /// Get all the nodes in this container
        /// This function does NOT check the containers inside this container
        /// also see AllNodes
        /// </summary>
        public virtual List<Node> LocalNodes
        {
            get
            {
                List<Node> nodes = new List<Node>();
                foreach (Item i in _Items.Values)
                {
                    if (i is Node)
                        nodes.Add((Node)i);                    
                }
                return nodes;
            }
        }
        /// <summary>
        /// Get all the nodes in this container
        /// This function does NOT check the containers inside this container
        /// Use AllNodes to get all the edges (recursively)
        /// </summary>
        public virtual List<Species> LocalSpecies
        {
            get
            {
                List<Species> nodes = new List<Species>();
                foreach (Item i in _Items.Values)
                {
                    if (i is Species)
                        nodes.Add((Species)i);
                }
                return nodes;
            }
        }
        /// <summary>
        /// Get all the nodes in this container
        /// This function does NOT check the containers inside this container
        /// also see AllParts
        /// </summary>
        public virtual List<Part> LocalParts
        {
            get
            {
                List<Part> nodes = new List<Part>();
                foreach (Item i in _Items.Values)
                {
                    if (i is Part)
                        nodes.Add((Part)i);
                }
                return nodes;
            }
        }
        /// <summary>
        /// Get all the modules in this container
        /// This function does NOT check the containers inside this container        
        /// also see AllItems
        /// </summary>
        public virtual List<Module> LocalModules
        {
            get
            {
                List<Module> mods = new List<Module>();
                foreach (Item i in _Items.Values)
                {
                    if (i is Module)
                        mods.Add((Module)i);                    
                }
                return mods;
            }
        }
        /// <summary>
        /// Get all the items in this container
        /// This function does NOT check the containers inside this container        
        /// also see AllItems. Adding to or removing from this list will not 
        /// add or remove items in the module. 
        /// </summary>
        public virtual List<Item> LocalItems
        {
            get
            {
                List<Item> mods = new List<Item>();
                foreach (Item i in _Items.Values)
                {
                    if (i is Item)
                        mods.Add(i);
                }
                return mods;
            }
        }

        /// <summary>
        /// Get all the items in this container as a Hashtable
        /// This function does NOT check the containers inside this container        
        /// also see AllItems. Adding to or removing from this list WILL 
        /// add or remove items in the module. Use with caution: altering this
        /// hashtable could potentially upset the module. 
        /// </summary>
        public virtual Hashtable LocalItemsHash
        {
            get
            {
                return _Items;
            }
        }
        /// <summary>
        /// Find the reaction that matches the given set of inputs/outputs/modifiers
        /// </summary>
        /// <param name="inputs"></param>
        /// <param name="outputs"></param>
        /// <param name="modifiers"></param>
        /// <returns></returns>
        public virtual Edge FindReaction(List<Item> inputs, List<Item> outputs, List<Item> modifiers)
        {
            ICollection<Core.Edge> edges = (ICollection<Core.Edge>)AllReactions;
            foreach (Edge e in edges)
            {
                bool match = true;

                if (e.Reactants.Length == inputs.Count)  //same number of inputs
                {
                    foreach (Node n in e.Reactants)  //each input contained
                    {
                        if (!inputs.Contains(n))
                        {
                            match = false;
                            break;
                        }
                    }
                }
                else
                {
                    match = false;
                }

                if (e.Products.Length == outputs.Count)  //same number of outputs
                {
                    foreach (Node n in e.Products)  //each output contained
                    {
                        if (!outputs.Contains(n))
                        {
                            match = false;
                            break;
                        }
                    }
                }
                else
                {
                    match = false;
                }

                if (e.Modifiers.Length == modifiers.Count)  //same number of modifiers
                {
                    foreach (Node n in e.Modifiers)  //each modifiers contained
                    {
                        if (!modifiers.Contains(n))
                        {
                            match = false;
                            break;
                        }
                    }
                }
                else
                {
                    match = false;
                }


                if (match)
                {
                    return e;
                }
            }
            return null;
        }

        /// <summary>
        /// Finds the item with the given full id inside the given hashtable. Use 
        /// either AllItems or AllItemsWithPrefix for the hashtable argument. AllItems
        /// will only include parent names are prefix if needed (when item is non-unique). 
        /// </summary>
        /// <param name="IDwithPrefix">an ID with or without its parent's names are prefix</param>
        /// <param name="allItemsWithPrefix">AllItems or AllItemsWithPrefix</param>
        /// <returns></returns>
        public virtual Item FindItem(string IDwithPrefix, Hashtable allItemsWithPrefix)
        {
            if (IDwithPrefix.Equals(Module.Empty.ID)) return Module.Empty;
            if (allItemsWithPrefix == null) return null;

            foreach (string s in allItemsWithPrefix.Keys)
            {
                if (s == IDwithPrefix)
                    return allItemsWithPrefix[s] as Item;
            }

            //search up
            if (ParentModule != null) 
                return ParentModule.FindItem(IDwithPrefix, ParentModule.AllItemsWithPrefix);

            return null;
        }

        /// <summary>
        /// Returns the item that has the given ID
        /// (recursively searches upwards)
        /// </summary>
        /// <param name="ID">ID</param>
        /// <returns>Item</returns>
        public virtual Item FindItem(string sID, bool searchOutside)
        {
            if (sID.Equals(Module.Empty.ID)) return Module.Empty;

            if (_Items == null) _Items = new Hashtable();

            Hashtable items = _Items;

            foreach (string id in items.Keys)
            {
                Item item = items[id] as Item;
                if (item != null)
                {
                    if (sID.Equals(id))
                        return item;
                }
            }

            foreach (object o in items.Values)
            {
                Item item = o as Item;
                if (item != null)
                {
                    if (item is Container)
                    {
                        Item id2 = ((Container)item).FindItem(sID, false);
                        if (id2 != null)
                            return id2;
                    }
                }
            }

            if (searchOutside)
            {
                if (Parent is Container)
                    return ((Container)Parent).FindItem(sID);
            }
            
            return null;
        }

        /// <summary>
        /// Find an Item inside this module or outside
        /// </summary>
        /// <param name="id">ID</param>
        /// <returns>Item</returns>
        public Item FindItem(string id)
        {
            return FindItem(id, true);
        }

        /// <summary>
        /// Finds the concentration if the given ID is a species
        /// Finds the rate is given ID is a reaction or part
        /// </summary>
        /// <param name="sId">ID</param>
        /// <returns>concentration or rate or null</returns>
        public virtual object this[string sId]
        {
            get
            {
                Item i = FindItem(sId);
                if (i is Species) return ((Species)i).Concentration;
                if (i is Edge) return ((Edge)i).Rate;
                if (i is Part && ((Part)i).PoPS != null) return ((Part)i).PoPS.Rate;
                return null;
            }
            set
            {
                if (!((value is Item) || (value is double) || (value is float) || (value is int) || (value is string))) return;
                
                Item i = FindItem(sId);

                if (i == null) return;

                if (value is Item)
                {
                    Module module = i.ParentModule;

                    if (module == null) return;

                    if (module._Items.ContainsKey(i.ID))
                    {
                        module._Items[i.ID] = value as Item;
                    }
                    return;
                }

                double d = -1d;
                if (value is double) d = (double)value;
                if (value is int) d = (int)value;
                if (value is float) d = (float)value;

                if (d >= 0 && i is Species)
                {
                    ((Species)i).Concentration = d;
                    return;
                }
                if (value is string && i is Edge)
                {
                    ((Edge)i).Rate = (string)value;
                    return;
                }
                if (value is string && i is Part && ((Part)i).PoPS != null)
                {
                    ((Part)i).PoPS.Rate = (string)value;
                    return;
                }
            }
        }

        /// <summary>
        /// writes each item in this module into xml as well as module parameters
        /// </summary>
        /// <param name="writer"></param>
        public override void WriteXML(XmlWriter writer)
        {
            base.WriteXML(writer);

            if (_Items.Count > 0)
            {
                writer.WriteStartElement("Container", "");

                writer.WriteStartElement("Items", "");

                foreach (Item item in _Items.Values)
                {
                    if (item is Container)
                        IO.XMLWriter.WriteItem(item, this, writer);
                }

                foreach (Item item in _Items.Values)
                {
                    if (item is Species)
                        IO.XMLWriter.WriteItem(item, this, writer);
                }

                foreach (Item item in _Items.Values)
                {
                    if (item is Part)
                        IO.XMLWriter.WriteItem(item, this, writer);
                }

                IO.XMLWriter.WriteItem(Module.Empty, this, writer);

                foreach (Item item in _Items.Values)
                {
                    if (item is Edge)
                        IO.XMLWriter.WriteItem(item, this, writer);
                }

                writer.WriteEndElement(); //end items
                writer.WriteEndElement();
            }
        }

        /// <summary>
        /// reads all the parameters and each node
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public override bool ReadXML(XmlReader reader)
        {
            bool read = base.ReadXML(reader);

            if (!(reader.NodeType == XmlNodeType.Element && reader.Name == "Container"))
                read = reader.Read();

            if (reader.NodeType == XmlNodeType.Element && reader.Name == "Container")
            {
                read = reader.Read();
                Hashtable parameters = new Hashtable();
                Drawable = new Objects.ContainerGlyph();

                while (read)
                {
                    if (reader.NodeType == XmlNodeType.EndElement)
                        break;

                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        switch (reader.Name)
                        {
                            case "Items":
                                while (read)
                                {
                                    Item item = IO.XMLReader.ReadItem(reader, this);
                                    if (item == null)
                                        break;
                                    else
                                    {
                                        AddItem(item);                                 
                                    }
                                    read = reader.Read();
                                }
                                break;
                            default:
                                while (reader.NodeType != XmlNodeType.EndElement)
                                    read = reader.Read();
                                break;
                        }
                    }
                    if (!read || (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Container")) break;
                    if (reader.NodeType != XmlNodeType.Element)
                        read = reader.Read();
                }
                return true;
            }
            return false;
        }
    }
}
